# -*- coding:utf-8 -*-

from urllib.parse import urljoin
from minio import Minio
from minio.commonconfig import ComposeSource, REPLACE
from minio.error import S3Error
from minio.deleteobjects import DeleteObject

from config.env import MinioConfig


class MinioService:
    def __init__(self):
        self.client = Minio(
            MinioConfig.minio_endpoint,
            access_key=MinioConfig.minio_access_key,
            secret_key=MinioConfig.minio_secret_key,
            secure=MinioConfig.minio_secure
        )

    async def create_bucket(self, bucket_name: str):
        try:
            if not self.client.bucket_exists(bucket_name):
                self.client.make_bucket(bucket_name)
            return True
        except S3Error as e:
            print(e)
        return False

    async def upload(self, file: bytes, filename: str, length: int, content_type: str, bucket_name: str = MinioConfig.minio_bucket_name):
        try:
            if not await self.create_bucket(bucket_name):
                return False
            self.client.put_object(
                bucket_name,
                filename,
                file,
                length=length,
                content_type=content_type
            )
            return urljoin(f'{MinioConfig.minio_base_url}', bucket_name + '/' + filename)
        except S3Error as e:
            print(e)
        return False
        
    async def download(self, filename: str, bucket_name: str = MinioConfig.minio_bucket_name):
        try:
            data = self.client.get_object(bucket_name, filename)
            return data.read()
        except S3Error as e:
            print(e)
    
    async def get_object(self, filename: str, bucket_name: str = MinioConfig.minio_bucket_name):
        try:
            return self.client.get_object(bucket_name, filename)
        except S3Error as e:
            print(e)
    
    async def get_file_info(self, filename: str, bucket_name: str = MinioConfig.minio_bucket_name):
        try:
            return self.client.stat_object(bucket_name, filename)
        except S3Error as e:
            print(e)

    async def get_url(self, filename: str, bucket_name: str = MinioConfig.minio_bucket_name):
        try:
            return self.client.presigned_get_object(bucket_name, filename)
        except S3Error as e:
            print(e)

    async def compose_object(self, object_name: str, path: str, metadata: dict, bucket_name: str = MinioConfig.minio_bucket_name)->str:
        try:
            objects = await self.list_objects(path)
            sources = [ComposeSource(bucket_name, item.object_name) for item in objects]
            self.client.compose_object(bucket_name, object_name, sources, metadata=metadata)
            return urljoin(MinioConfig.minio_base_url, f'{bucket_name}/{object_name}')
        except S3Error as e:
            print(e)
    
    async def list_objects(self, prefix: str = '', bucket_name: str = MinioConfig.minio_bucket_name)->list:
        try:
            return self.client.list_objects(bucket_name, prefix=prefix)
        except S3Error as e:
            print(e)

    async def remove_objects(self, path: str, bucket_name: str = MinioConfig.minio_bucket_name)->list:
        result = []
        try:
            delete_object_list = map(
                lambda x: DeleteObject(x.object_name),
                await self.list_objects(path)
            )
            result = self.client.remove_objects(bucket_name, delete_object_list)
            result = [item.object_name for item in result]
            return result
        except S3Error as e:
            print(e)
        return result
